package com.engr.springbooteasypoi.thread;

import java.util.concurrent.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author : liuYanXin
 * @Description : 条件变量
 * @Date : 2020-03-27
 */
public class ConditionCls {

    public static void main(String[] args) {

        ConditionCount conditionCount = new ConditionCount("A", 500);
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
                5, 10, 20L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(),
                Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        DrawThread d1 = new DrawThread("d1", conditionCount, 20);
        SaveThread s4 = new SaveThread("s4", 30, conditionCount);
        DrawThread d2 = new DrawThread("d2", conditionCount, 20);
        SaveThread s3 = new SaveThread("s3", 30, conditionCount);
        SaveThread s1 = new SaveThread("s1", 30, conditionCount);
        DrawThread d3 = new DrawThread("d3", conditionCount, 20);
        SaveThread s2 = new SaveThread("s2", 30, conditionCount);
        poolExecutor.submit(d1);
        poolExecutor.execute(s4);
        poolExecutor.submit(d2);
        poolExecutor.submit(d3);
        poolExecutor.submit(s2);
        poolExecutor.submit(s1);
        poolExecutor.submit(s3);
        poolExecutor.shutdown();

    }
}

class DrawThread implements Callable {

    private String name;

    private ConditionCount conditionCount;

    private int x;

    public DrawThread(String name, ConditionCount conditionCount, int x) {
        this.name = name;
        this.conditionCount = conditionCount;
        this.x = x;
    }

    @Override
    public Object call() throws Exception {
        conditionCount.drawing(x, name);
        return null;
    }
}


class SaveThread implements Runnable {

    private String name;

    private int x;

    private ConditionCount conditionCount;


    public SaveThread(String name, int x, ConditionCount conditionCount) {
        this.name = name;
        this.x = x;
        this.conditionCount = conditionCount;
    }

    @Override
    public void run() {
        conditionCount.saving(x, name);
    }
}


/**
 * 普通银行账户，不可透支
 */
class ConditionCount {

    private String oid;

    private int cash;

    private Lock lock = new ReentrantLock();

    private Condition _save = lock.newCondition();
    private Condition _draw = lock.newCondition();

    public ConditionCount(String oid, int cash) {
        this.oid = oid;
        this.cash = cash;
    }

    /**
     * 存款
     *
     * @param x    金额
     * @param name 姓名
     */
    public void saving(int x, String name) {
        lock.lock();
        try {
            if (x > 0) {
                cash += x;
                System.out.println(Thread.currentThread().getName() + "->" + name + "存款 " + x + ",当前余额为：" + cash);
                // 唤醒所有线程
                _draw.signalAll();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void drawing(int x, String name) {

        lock.lock();
        try {
            if (cash - x < 0) {
                _draw.wait();
            } else {
                cash -= x;
                System.out.println(Thread.currentThread().getName() + "->" + name + "取款 " + x + ",当前余额为：" + cash);
            }
            _save.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
}
